﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Spk.Controls.Common;

namespace Spk.Controls.Trees
{
    /// <summary>
    /// States of virtual node
    /// </summary>
    /// <remarks>
    /// You shall be extremely careful, when adding new elements
    /// to this enumeration, especially, if the new element 
    /// corresponds to some field in the VirtualTreeView, such
    /// as Selected, Focused, ShiftSelectionOrigin and so on.
    /// There are numerous occasions, when such state of node
    /// changes and shall be synchronized with VTV fields.
    /// These ocasions include expanding or collapsing, showing
    /// or hiding and deleting node (or its parent).
    /// </remarks>
    [Flags]
    internal enum VirtualNodeStates
    {
        UserInitiated = 1,
        HasChildren = 2,
        Visible = 4,
        Measured = 8,
        Expanded = 16,
        Selected = 32,
        Focused = 64,
        Checked = 128,
        HotTrack = 256,
        ShiftSelectionOrigin = 512
    }

    public class VirtualNode
    {
        // Private fields ----------------------------------------------------

        private VirtualTreeView ownerTree = null;
        private VirtualNode parent = null;
        private VirtualNode previousSibling = null;
        private VirtualNode nextSibling = null;
        private VirtualNode firstChild = null;
        private VirtualNode lastChild = null;
        private object data = null;
        private uint childCount = 0;
        private uint index = 0;
        private uint height = 0;
        private uint totalHeight = 0;
        private VirtualNodeStates states = VirtualNodeStates.Visible;

        // Public methods ----------------------------------------------------

        public VirtualNode()
        {
            
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            sb.Append("Node ");
            sb.Append(index.ToString());

            if (Data != null)
                sb.Append(" {").Append(data.ToString()).Append("}");

            return sb.ToString();
        }

        // Internal properties -----------------------------------------------

        internal VirtualTreeView OwnerTree
        {
            get
            {
                return ownerTree;
            }
            set
            {
                ownerTree = value;
            }
        }

        // Public properties -------------------------------------------------

        /// <summary>
        /// Parent node
        /// </summary>
        public VirtualNode Parent
        { 
            get 
            { 
                return parent; 
            }
            internal set 
            { 
                parent = value; 
            } 
        }

        /// <summary>
        /// Previous sibling
        /// </summary>
        public VirtualNode PreviousSibling
        {
            get 
            { 
                return previousSibling; 
            }
            internal set 
            { 
                previousSibling = value; 
            }
        }

        /// <summary>
        /// Next sibling
        /// </summary>
        public VirtualNode NextSibling 
        { 
            get
            {
                return nextSibling;
            } 
            internal set
            {
                nextSibling = value;   
            } 
        }

        /// <summary>
        /// First child
        /// </summary>
        public VirtualNode FirstChild
        {
            get
            {
                return firstChild;
            }
            internal set
            {
                firstChild = value;   
            } 
        }

        /// <summary>
        /// Last child
        /// </summary>
        public VirtualNode LastChild
        {
            get
            {
                return lastChild;
            }
            internal set
            {
                lastChild = value;
            }
        }

        /// <summary>
        /// A placeholder for user data.
        /// </summary>
        public object Data 
        { 
            get
            {
                return data;
            }
            internal set
            {
                data = value;
            }
        }

        /// <summary>
        /// Count of children of this node
        /// </summary>
        public uint ChildCount 
        { 
            get
            {
                return childCount;   
            }
            internal set
            {
                childCount = value;
            }
        }

        /// <summary>
        /// Index of this node in parent's child list.
        /// </summary>
        public uint Index
        {
            get
            {
                return index;
            }
            internal set
            {
                index = value;
            }
        }

        /// <summary>
        /// Height of a node, in pixels.
        /// </summary>
        public uint Height
        {
            get
            {
                return height;
            }
            internal set
            {
                height = value;
            }
        }

        /// <summary>
        /// Height of a node, including all its visible children and subchildren, in pixels
        /// </summary>
        public uint TotalHeight 
        {
            get
            {
                return totalHeight;
            }
            internal set
            {
                totalHeight = value;
            }
        }

        // *** Shortcut properties ***

        /// <summary>
        /// Checks, if the node is a root node of a tree.
        /// The root node serves as a root for all visible
        /// nodes in tree, but itself is never visible.
        /// </summary>
        public bool IsRoot
        {
            get
            {
                return parent == null;
            }
        }

        /// <summary>
        /// Checks, if the node is used by a tree control.
        /// If the node is not valid, it should be disposed of.
        /// </summary>
        public bool IsValid
        {
            get
            {
                return ownerTree != null;
            }
        }

        public bool IsUserInitiated
        {
            get
            {
                return (states & VirtualNodeStates.UserInitiated) != 0;
            }
            internal set
            {
                if (value) 
                    states |= VirtualNodeStates.UserInitiated; 
                else 
                    states &= ~VirtualNodeStates.UserInitiated;
            }
        }

        public bool HasChildren
        {
            get
            {
                return (states & VirtualNodeStates.HasChildren) != 0;
            }
            internal set
            {
                if (value) 
                    states |= VirtualNodeStates.HasChildren; 
                else 
                    states &= ~VirtualNodeStates.HasChildren;
            }
        }

        public bool IsVisible
        {
            get
            {
                return (states & VirtualNodeStates.Visible) != 0;
            }
            internal set
            {
                if (value) 
                    states |= VirtualNodeStates.Visible; 
                else 
                    states &= ~VirtualNodeStates.Visible;
            }
        }

        public bool IsMeasured
        {
            get
            {
                return (states & VirtualNodeStates.Measured) != 0;
            }
            internal set
            {
                if (value) 
                    states |= VirtualNodeStates.Measured; 
                else 
                    states &= ~VirtualNodeStates.Measured;
            }
        }

        public bool IsExpanded
        {
            get
            {
                return (states & VirtualNodeStates.Expanded) != 0;
            }
            internal set
            {
                if (value)
                    states |= VirtualNodeStates.Expanded;
                else
                    states &= ~VirtualNodeStates.Expanded;
            }
        }

        public bool IsSelected
        {
            get
            {
                return (states & VirtualNodeStates.Selected) != 0;
            }
            internal set
            {
                if (value) 
                    states |= VirtualNodeStates.Selected; 
                else 
                    states &= ~VirtualNodeStates.Selected;
            }
        }

        public bool IsFocused
        {
            get
            {
                return (states & VirtualNodeStates.Focused) != 0;
            }
            internal set
            {
                if (value) 
                    states |= VirtualNodeStates.Focused; 
                else 
                    states &= ~VirtualNodeStates.Focused;
            }
        }

        public bool IsChecked
        {
            get
            {
                return (states & VirtualNodeStates.Checked) != 0;
            }
            internal set
            {
                if (value)
                    states |= VirtualNodeStates.Checked;
                else
                    states &= ~VirtualNodeStates.Checked;
            }
        }

        public bool IsHotTrack
        {
            get
            {
                return (states & VirtualNodeStates.HotTrack) != 0;
            }
            internal set
            {
                if (value)
                    states |= VirtualNodeStates.HotTrack;
                else
                    states &= ~VirtualNodeStates.HotTrack;
            }
        }

        public bool IsShiftSelectionOrigin
        {
            get
            {
                return (states & VirtualNodeStates.ShiftSelectionOrigin) != 0;
            }
            internal set
            {
                if (value) 
                    states |= VirtualNodeStates.ShiftSelectionOrigin; 
                else 
                    states &= ~VirtualNodeStates.ShiftSelectionOrigin;
            }
        }

        /// <summary>
        /// Checks, if node is its parent's first child
        /// </summary>
        public bool IsFirstChild
        {
            get
            {
                return previousSibling == null;
            }
        }

        /// <summary>
        /// Checks, if node is its parent's last child
        /// </summary>
        public bool IsLastChild
        {
            get
            {
                return nextSibling == null;
            }
        }
    }

    internal static class VirtualNodeHelper
    {
        public static void CheckOwnerTree(this VirtualNode node, VirtualTreeView tree, string name)
        {
            if (node == null)
                throw new ArgumentException(name);
            if (node.OwnerTree != tree)
                throw new ArgumentException(name);
        }        
    }
}
